using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using Engine;
using LiteNetLib;
using LiteNetLib.Utils;

namespace Game
{
	[Extension]
	public static class NetworkManager
	{
		private class PeerInfoPacket
		{
			[CompilerGenerated]
			private int _003CPeerStage_003Ek__BackingField;

			[CompilerGenerated]
			private Guid _003CUserId_003Ek__BackingField;

			public int PeerStage
			{
				[CompilerGenerated]
				get
				{
					return _003CPeerStage_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CPeerStage_003Ek__BackingField = value;
				}
			}

			public Guid UserId
			{
				[CompilerGenerated]
				get
				{
					return _003CUserId_003Ek__BackingField;
				}
				[CompilerGenerated]
				set
				{
					_003CUserId_003Ek__BackingField = value;
				}
			}
		}

		public enum PeerStage
		{
			Invalid,
			Connected,
			DownloadingWorld,
			NotReady,
			Ready
		}

		public class PeerData
		{
			public PeerStage PeerStage;

			public Guid UserId;

			public Dictionary<PeerStage, Queue<Action>> PendingPackets;

			public PeerData(PeerStage peerStage, Guid userId)
			{
				Dictionary<PeerStage, Queue<Action>> dictionary = new Dictionary<PeerStage, Queue<Action>>();
				dictionary.Add(PeerStage.Invalid, new Queue<Action>());
				dictionary.Add(PeerStage.Connected, new Queue<Action>());
				dictionary.Add(PeerStage.DownloadingWorld, new Queue<Action>());
				dictionary.Add(PeerStage.NotReady, new Queue<Action>());
				dictionary.Add(PeerStage.Ready, new Queue<Action>());
				PendingPackets = dictionary;
				base._002Ector();
				PeerStage = peerStage;
				UserId = userId;
			}
		}

		[CompilerGenerated]
		private sealed class _003Cget_ReadyPeers_003Ed__25 : IEnumerable<PeerData>, IEnumerable, IEnumerator<PeerData>, IDisposable, IEnumerator
		{
			private int _003C_003E1__state;

			private PeerData _003C_003E2__current;

			private int _003C_003El__initialThreadId;

			private List<NetPeer>.Enumerator _003C_003E7__wrap1;

			PeerData IEnumerator<PeerData>.Current
			{
				[DebuggerHidden]
				get
				{
					return _003C_003E2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return _003C_003E2__current;
				}
			}

			[DebuggerHidden]
			public _003Cget_ReadyPeers_003Ed__25(int _003C_003E1__state)
			{
				this._003C_003E1__state = _003C_003E1__state;
				_003C_003El__initialThreadId = Environment.CurrentManagedThreadId;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = _003C_003E1__state;
				if (num == -3 || num == 1)
				{
					try
					{
					}
					finally
					{
						_003C_003Em__Finally1();
					}
				}
			}

			private bool MoveNext()
			{
				try
				{
					switch (_003C_003E1__state)
					{
					default:
						return false;
					case 0:
						_003C_003E1__state = -1;
						_003C_003E7__wrap1 = Manager.ConnectedPeerList.GetEnumerator();
						_003C_003E1__state = -3;
						break;
					case 1:
						_003C_003E1__state = -3;
						break;
					}
					while (_003C_003E7__wrap1.MoveNext())
					{
						PeerData peerData = _003C_003E7__wrap1.Current.Tag as PeerData;
						if (peerData.PeerStage == PeerStage.Ready)
						{
							_003C_003E2__current = peerData;
							_003C_003E1__state = 1;
							return true;
						}
					}
					_003C_003Em__Finally1();
					_003C_003E7__wrap1 = default(List<NetPeer>.Enumerator);
					return false;
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void _003C_003Em__Finally1()
			{
				_003C_003E1__state = -1;
				((IDisposable)_003C_003E7__wrap1/*cast due to .constrained prefix*/).Dispose();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}

			[DebuggerHidden]
			IEnumerator<PeerData> IEnumerable<PeerData>.GetEnumerator()
			{
				if (_003C_003E1__state == -2 && _003C_003El__initialThreadId == Environment.CurrentManagedThreadId)
				{
					_003C_003E1__state = 0;
					return this;
				}
				return new _003Cget_ReadyPeers_003Ed__25(0);
			}

			[DebuggerHidden]
			IEnumerator IEnumerable.GetEnumerator()
			{
				return ((IEnumerable<PeerData>)this).GetEnumerator();
			}
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class _003C_003Ec
		{
			public static readonly _003C_003Ec _003C_003E9 = new _003C_003Ec();

			public static Action<NetDataWriter, Guid> _003C_003E9__29_0;

			public static Func<NetDataReader, Guid> _003C_003E9__29_1;

			public static Func<IPAddress, bool> _003C_003E9__29_2;

			internal void _003CStart_003Eb__29_0(NetDataWriter w, Guid g)
			{
				w.Put(g.ToByteArray());
			}

			internal Guid _003CStart_003Eb__29_1(NetDataReader r)
			{
				byte[] array = new byte[16];
				r.GetBytes(array, 16);
				return new Guid(array);
			}

			internal bool _003CStart_003Eb__29_2(IPAddress a)
			{
				return a.AddressFamily == AddressFamily.InterNetwork;
			}
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class _003C_003Ec__39<T> where T : class, INetSerializable, new()
		{
			public static readonly _003C_003Ec__39<T> _003C_003E9 = new _003C_003Ec__39<T>();

			public static Func<T> _003C_003E9__39_0;

			internal T _003CRegisterPacketClass_003Eb__39_0()
			{
				return new T();
			}
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class _003C_003Ec__41<T> where T : struct
		{
			public static readonly _003C_003Ec__41<T> _003C_003E9 = new _003C_003Ec__41<T>();

			public static Action<NetDataWriter, T> _003C_003E9__41_0;

			public static Func<NetDataReader, T> _003C_003E9__41_1;

			internal void _003CRegisterStructPacket_003Eb__41_0(NetDataWriter w, T p)
			{
				NetworkSerializer.Write(w, p);
			}

			internal T _003CRegisterStructPacket_003Eb__41_1(NetDataReader r)
			{
				return NetworkSerializer.Read<T>(r);
			}
		}

		[CompilerGenerated]
		private sealed class _003C_003Ec__DisplayClass42_0<T> where T : class, new()
		{
			public NetPeer peer;

			public T packet;

			public DeliveryMethod method;

			internal void _003CSendPacket_003Eb__0()
			{
				peer.Send(packetProcessor_.Write(packet), method);
			}
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class _003C_003Ec__44<T> where T : class, new()
		{
			public static readonly _003C_003Ec__44<T> _003C_003E9 = new _003C_003Ec__44<T>();

			public static Func<T> _003C_003E9__44_0;

			internal T _003CSubscribePacket_003Eb__44_0()
			{
				return new T();
			}
		}

		private const string ClientIdLocation = "data:/ClientId.dat";

		public const int DEFAULT_PORT = 50550;

		private static readonly NetPacketProcessor packetProcessor_ = new NetPacketProcessor();

		public static IPAddress LocalAddress;

		[CompilerGenerated]
		private static NetManager _003CManager_003Ek__BackingField;

		[CompilerGenerated]
		private static EventBasedNetListener _003CListener_003Ek__BackingField;

		private static PeerStage clientStage_ = PeerStage.NotReady;

		private static Guid clientId_ = Guid.Empty;

		public static NetManager Manager
		{
			[CompilerGenerated]
			get
			{
				return _003CManager_003Ek__BackingField;
			}
			[CompilerGenerated]
			private set
			{
				_003CManager_003Ek__BackingField = value;
			}
		}

		public static EventBasedNetListener Listener
		{
			[CompilerGenerated]
			get
			{
				return _003CListener_003Ek__BackingField;
			}
			[CompilerGenerated]
			private set
			{
				_003CListener_003Ek__BackingField = value;
			}
		}

		public static PeerStage ClientStage
		{
			get
			{
				return clientStage_;
			}
			set
			{
				if (clientStage_ != value)
				{
					Log.Information("Client stage changed to: " + value);
					clientStage_ = value;
					SendPacketToAll(CreatePeerInfoPackt(), DeliveryMethod.ReliableOrdered, PeerStage.Invalid);
				}
			}
		}

		public static IEnumerable<PeerData> ReadyPeers
		{
			[IteratorStateMachine(typeof(_003Cget_ReadyPeers_003Ed__25))]
			get
			{
				return new _003Cget_ReadyPeers_003Ed__25(-2);
			}
		}

		public static Guid ClientId
		{
			get
			{
				if (clientId_ == Guid.Empty)
				{
					if (Storage.FileExists("data:/ClientId.dat"))
					{
						clientId_ = Guid.Parse(Storage.ReadAllText("data:/ClientId.dat"));
					}
					else
					{
						clientId_ = Guid.NewGuid();
						Storage.WriteAllText("data:/ClientId.dat", clientId_.ToString());
					}
				}
				return clientId_;
			}
		}

		public static event Action<NetPeer> PeerStateChanged;

		[Extension]
		public static PeerData GetData(NetPeer peer)
		{
			return peer.Tag as PeerData;
		}

		private static PeerInfoPacket CreatePeerInfoPackt()
		{
			PeerInfoPacket peerInfoPacket = new PeerInfoPacket();
			peerInfoPacket.PeerStage = (int)clientStage_;
			peerInfoPacket.UserId = ClientId;
			return peerInfoPacket;
		}

		public static void Start()
		{
			Listener = new EventBasedNetListener();
			Manager = new NetManager(Listener);
			packetProcessor_.RegisterNestedType<LJPeers>();
			packetProcessor_.RegisterNestedType(_003C_003Ec._003C_003E9__29_0 ?? (_003C_003Ec._003C_003E9__29_0 = new Action<NetDataWriter, Guid>(_003C_003Ec._003C_003E9._003CStart_003Eb__29_0)), _003C_003Ec._003C_003E9__29_1 ?? (_003C_003Ec._003C_003E9__29_1 = new Func<NetDataReader, Guid>(_003C_003Ec._003C_003E9._003CStart_003Eb__29_1)));
			Listener.NetworkReceiveEvent += new EventBasedNetListener.OnNetworkReceive(OnReciveData);
			Listener.ConnectionRequestEvent += new EventBasedNetListener.OnConnectionRequest(OnConnectionRequest);
			Listener.PeerDisconnectedEvent += new EventBasedNetListener.OnPeerDisconnected(OnPeerDisconnected);
			SubscribeReusablePacket(new Action<PeerInfoPacket, NetPeer>(OnPeerInfoPacket));
			Manager.Start(50550);
			LocalAddress = Enumerable.FirstOrDefault(Dns.GetHostAddresses(Dns.GetHostName()), _003C_003Ec._003C_003E9__29_2 ?? (_003C_003Ec._003C_003E9__29_2 = new Func<IPAddress, bool>(_003C_003Ec._003C_003E9._003CStart_003Eb__29_2)));
			if (LocalAddress == null)
			{
				LocalAddress = IPAddress.None;
			}
			IPAddress localAddress = LocalAddress;
			Log.Information("starting server at " + ((localAddress != null) ? localAddress.ToString() : null) + ":" + Manager.LocalPort);
			Window.Frame += new Action(Update);
		}

		private static void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo)
		{
			SetPeerState(peer, PeerStage.Invalid, (peer.Tag as PeerData).UserId);
		}

		public static void SendConnectionRequest(IPEndPoint endpoint)
		{
			NetDataWriter netDataWriter = new NetDataWriter();
			packetProcessor_.Write(netDataWriter, CreatePeerInfoPackt());
			Manager.Connect(endpoint, netDataWriter).Tag = new PeerData(PeerStage.Invalid, Guid.Empty);
		}

		private static void OnConnectionRequest(ConnectionRequest request)
		{
			IPEndPoint remoteEndPoint = request.RemoteEndPoint;
			Log.Information("Connection request from: " + ((remoteEndPoint != null) ? remoteEndPoint.ToString() : null));
			NetPeer netPeer = null;
			try
			{
				netPeer = request.Accept();
				packetProcessor_.ReadPacket(request.Data, netPeer);
				SendPacket(netPeer, CreatePeerInfoPackt(), DeliveryMethod.ReliableOrdered, PeerStage.Invalid);
			}
			catch (ParseException)
			{
				if (netPeer != null)
				{
					netPeer.Disconnect();
				}
			}
		}

		private static void OnPeerInfoPacket(PeerInfoPacket packet, NetPeer peer)
		{
			PeerData peerData = peer.Tag as PeerData;
			if (peerData == null)
			{
				peerData = new PeerData((PeerStage)packet.PeerStage, packet.UserId);
				peer.Tag = peerData;
				Action<NetPeer> peerStateChanged = NetworkManager.PeerStateChanged;
				if (peerStateChanged != null)
				{
					peerStateChanged(peer);
				}
			}
			else
			{
				SetPeerState(peer, (PeerStage)packet.PeerStage, packet.UserId);
			}
		}

		private static void SetPeerState(NetPeer peer, PeerStage peerStage, Guid userId)
		{
			PeerData peerData = peer.Tag as PeerData;
			if (peerData.PeerStage != peerStage)
			{
				peerData.PeerStage = peerStage;
				peerData.UserId = userId;
				Action<NetPeer> peerStateChanged = NetworkManager.PeerStateChanged;
				if (peerStateChanged != null)
				{
					peerStateChanged(peer);
				}
				Queue<Action> val = peerData.PendingPackets[peerStage];
				for (int i = 0; i < val.Count; i++)
				{
					val.Dequeue()();
				}
			}
		}

		public static void Stop()
		{
			Manager.Stop();
			Window.Frame -= new Action(Update);
		}

		public static void Update()
		{
			Manager.PollEvents();
		}

		private static void OnReciveData(NetPeer peer, NetPacketReader reader, DeliveryMethod method)
		{
			try
			{
				packetProcessor_.ReadAllPackets(reader, peer);
				reader.Recycle();
			}
			catch (ParseException ex)
			{
				Log.Error("error reading packet: " + ex.Message);
			}
		}

		public static bool RegisterPacketData<T>() where T : struct, INetSerializable
		{
			return packetProcessor_.RegisterNestedType<T>();
		}

		public static bool RegisterPacketClass<T>() where T : class, INetSerializable, new()
		{
			return packetProcessor_.RegisterNestedType(_003C_003Ec__39<T>._003C_003E9__39_0 ?? (_003C_003Ec__39<T>._003C_003E9__39_0 = new Func<T>(_003C_003Ec__39<T>._003C_003E9._003CRegisterPacketClass_003Eb__39_0)));
		}

		public static bool RegisterPacket<T>(Action<NetDataWriter, T> writer, Func<NetDataReader, T> reader)
		{
			return packetProcessor_.RegisterNestedType(writer, reader);
		}

		public static bool RegisterStructPacket<T>() where T : struct
		{
			return packetProcessor_.RegisterNestedType(_003C_003Ec__41<T>._003C_003E9__41_0 ?? (_003C_003Ec__41<T>._003C_003E9__41_0 = new Action<NetDataWriter, T>(_003C_003Ec__41<T>._003C_003E9._003CRegisterStructPacket_003Eb__41_0)), _003C_003Ec__41<T>._003C_003E9__41_1 ?? (_003C_003Ec__41<T>._003C_003E9__41_1 = new Func<NetDataReader, T>(_003C_003Ec__41<T>._003C_003E9._003CRegisterStructPacket_003Eb__41_1)));
		}

		public static void SendPacket<T>(NetPeer peer, T packet, DeliveryMethod method, PeerStage stage) where T : class, new()
		{
			_003C_003Ec__DisplayClass42_0<T> _003C_003Ec__DisplayClass42_ = new _003C_003Ec__DisplayClass42_0<T>();
			_003C_003Ec__DisplayClass42_.peer = peer;
			_003C_003Ec__DisplayClass42_.packet = packet;
			_003C_003Ec__DisplayClass42_.method = method;
			PeerData peerData = _003C_003Ec__DisplayClass42_.peer.Tag as PeerData;
			if (peerData.PeerStage >= stage)
			{
				_003C_003Ec__DisplayClass42_.peer.Send(packetProcessor_.Write(_003C_003Ec__DisplayClass42_.packet), _003C_003Ec__DisplayClass42_.method);
			}
			else if (_003C_003Ec__DisplayClass42_.method == DeliveryMethod.ReliableOrdered)
			{
				Type type = _003C_003Ec__DisplayClass42_.packet.GetType();
				Log.Information("add pending: " + (((object)type != null) ? type.ToString() : null));
				peerData.PendingPackets[stage].Enqueue(new Action(_003C_003Ec__DisplayClass42_._003CSendPacket_003Eb__0));
			}
		}

		public static void SendPacketToAll<T>(T packet, DeliveryMethod method, PeerStage stage) where T : class, new()
		{
			foreach (NetPeer connectedPeer in Manager.ConnectedPeerList)
			{
				SendPacket(connectedPeer, packet, method, stage);
			}
		}

		public static void SubscribePacket<T>(Action<T, NetPeer> action) where T : class, new()
		{
			packetProcessor_.Subscribe(action, _003C_003Ec__44<T>._003C_003E9__44_0 ?? (_003C_003Ec__44<T>._003C_003E9__44_0 = new Func<T>(_003C_003Ec__44<T>._003C_003E9._003CSubscribePacket_003Eb__44_0)));
		}

		public static void SubscribeReusablePacket<T>(Action<T, NetPeer> action) where T : class, new()
		{
			packetProcessor_.SubscribeReusable(action);
		}

		public static bool RemoveSubscribtion<T>()
		{
			if (packetProcessor_.RemoveSubscription<T>())
			{
				return true;
			}
			return false;
		}
	}
}
